package com.google.code.p.restrpc.client.proxy;

import java.lang.reflect.Method;
import java.util.List;

import com.google.code.p.restrpc.RestInvoker;
import com.google.code.p.restrpc.RpcContext;
import com.google.code.p.restrpc.RpcInvoker;
import com.google.code.p.restrpc.RpcRequest;
import com.google.code.p.restrpc.RpcResponse;
import com.google.code.p.restrpc.annotation.Implementor;
import com.google.code.p.restrpc.client.RpcResponseHandler;
import com.google.code.p.restrpc.client.event.AsyncRpcEventUtils;

/**
 * @author dz
 */
public abstract class AbstractRpcInvoker implements RpcInvoker {
    
    private RpcResponseHandler rpcResponseHandler = DefaultRpcResponseHandler.instance;
    
    private RestInvoker restInvoker;
    
    public AbstractRpcInvoker(RestInvoker restInvoker) {
        this.restInvoker = restInvoker;
    }
    
    /**
     * @param rpcInvoker
     */
    public void setRestInvoker(RestInvoker restInvoker) {
        this.restInvoker = restInvoker;
    }
    
    /**
     * @return
     */
    public RestInvoker getRestInvoker() {
        return restInvoker;
    }
    
    /**
     * @return
     */
    public RpcResponseHandler getRpcResponseHandler() {
        return rpcResponseHandler;
    }
    
    /**
     * @param handler
     */
    public void setRpcResponseHandler(RpcResponseHandler handler) {
        this.rpcResponseHandler = handler;
    }
    
    /**
     * 
     */
    public Object invoke(RpcContext rpcContext, RpcRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("request can not be null!");
        }
        
        RpcResponse response = getRestInvoker().send(request);
        if (response.isSucceed() && request.isAsync()) {
            AsyncRpcEventUtils.publishAsyncRpcEvent(rpcContext, request);
        }
        
        Method method = rpcContext.getTargetMethod();
        Implementor implementor = method.getAnnotation(Implementor.class);
        return getRpcResponseHandler().handle(response,
                                              implementor != null ? implementor.value()
                                                                 : method.getReturnType());
    }
    
    /**
     */
    public Object invoke(RpcContext rpcContext, List<RpcRequest> request) {
        throw new UnsupportedOperationException();
    }
    
}
